package com.kayb.patterns.behavioral;

import java.util.StringTokenizer;

/**
 * 解析器模式，定义一些语法规则，然后定义一个解析器去解析这些语法
 * @author huangkaibin
 * @date 2018-08-29
 **/
public class Interpreter {

    static abstract class Expression {
        public abstract boolean interpret(String str);
    }

    static class TerminalExpression extends Expression {

        private String literal = null;

        public TerminalExpression(String str) {
            literal = str;
        }

        public boolean interpret(String str) {
            StringTokenizer st = new StringTokenizer(str);
            while (st.hasMoreTokens()) {
                String test = st.nextToken();
                if (test.equals(literal)) {
                    return true;
                }
            }
            return false;
        }
    }

    static class AndExpression extends Expression {

        private Expression expression1 = null;
        private Expression expression2 = null;

        public AndExpression(Expression expression1, Expression expression2) {
            this.expression1 = expression1;
            this.expression2 = expression2;
        }

        public boolean interpret(String str) {
            return expression1.interpret(str) && expression2.interpret(str);
        }
    }

    static class OrExpression extends Expression {
        private Expression expression1 = null;
        private Expression expression2 = null;

        public OrExpression(Expression expression1, Expression expression2) {
            this.expression1 = expression1;
            this.expression2 = expression2;
        }

        public boolean interpret(String str) {
            return expression1.interpret(str) || expression2.interpret(str);
        }
    }

    /**
     * 构建解析树
     */
    public static Expression buildInterpreterTree() {
        // Literal
        Expression terminal1 = new TerminalExpression("A");
        Expression terminal2 = new TerminalExpression("B");
        Expression terminal3 = new TerminalExpression("C");
        Expression terminal4 = new TerminalExpression("D");
        // B C
        Expression alternation1 = new OrExpression(terminal2, terminal3);
        // A Or (B C)
        Expression alternation2 = new OrExpression(terminal1, alternation1);
        // D And (A Or (B C))
        return new AndExpression(terminal4, alternation2);
    }

    public static void main(String[] args) {
        Expression define = buildInterpreterTree();
        String context1 = "D A";
        String context2 = "A B";
        System.out.println(define.interpret(context1));
        System.out.println(define.interpret(context2));
    }

}
